package mango.web;

import java.io.IOException;
import java.util.Enumeration;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import mango.Mango;
import mango.functions.FuncServlet;
import mango.functions.FuncString;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

@SuppressWarnings("unchecked")
public class DispatchServlet extends HttpServlet {
    private static final long serialVersionUID = -4182104871944908447L;

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        try {
            FuncServlet.printRequest(request);
            String ret = this.process(request, response);
            if (ret != null && !response.isCommitted()) {
                Mango.getLog().info("RESPONSE|" + ret);
                response.getWriter().write(ret);
            }
        }
        catch(Exception e) {
            Mango.getLog().info("DOGET ERROR", e);
        }
    }

    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        try {
            FuncServlet.printRequest(request);
            String ret = this.process(request, response);
            if (ret != null && !response.isCommitted()) {
                Mango.getLog().info("RESPONSE|" + ret);
                response.getWriter().write(ret);
            }
        }
        catch(Exception e) {
            Mango.getLog().info("DOPOST ERROR", e);
        }
    }

    private String process(HttpServletRequest request, HttpServletResponse response) {
        Action act = null;
        String result = null;
        try {
            String actionName = FuncServlet.getRequestActionName(request);
            act = Action.getAction(actionName);
            if (act == null) {
                response.sendError(404);
                return null;
            }
            act.setRequest(request);
            act.setResponse(response);
            FormChain formChain = new FormChain(request);
            this.processRequest(request, act, formChain);
            boolean ret = act.service(formChain);
            result = act.getInfo();
            if (ret && FuncString.isBlank(result)){
                result = InfoMaker.getInstance().generateInfo(Info.SUCCESS, "OK").toJSON();
            }
            if (ret && act.getResult() != null) {
                result = act.getResult();
            }
            if(!ret && FuncString.isBlank(result)) {
                result = InfoMaker.getInstance().generateInfo(Info.ERROR, "Error").toJSON();
            }
        }
        catch (Exception e) {
            Mango.getLog().error("process", e);
            if (act != null) {
                act.handleException(e);
                result = act.getInfo();
            }
        }
        return result;
    }

    private void processRequest(HttpServletRequest request, Action act, FormChain formChain) throws Exception {
        String contentType = request.getContentType();
        if (contentType != null && contentType.contains("multipart/form-data")) {
            this.processMultiData(request, act, formChain);
        }
        else {
            this.processFormData(request, act, formChain);
        }
    }

    private void processMultiData(HttpServletRequest request, Action act, FormChain formChain) throws Exception {
        DiskFileItemFactory dfif = new DiskFileItemFactory();
        ServletFileUpload sfu = new ServletFileUpload(dfif);
        List<FileItem> itemList = sfu.parseRequest(request);
        for (FileItem item : itemList) {
            String fieldName = item.getFieldName();
            if (item.isFormField()) {
                formChain.setRequestParameter(fieldName, item.getString(Mango.getProperty(Mango.ENCODING)));
                if (Action.REQUEST_METHOD.equalsIgnoreCase(fieldName)) {
                    act.setMethod(item.getString());
                }
            }
            else {
                formChain.setRequestUploadStream(fieldName, item.getInputStream());
            }
        }
    }

    private void processFormData(HttpServletRequest request, Action act, FormChain formChain) {
        Enumeration<String> paramNames = request.getParameterNames();
        while (paramNames.hasMoreElements()) {
            String paramName = paramNames.nextElement();
            String[] paramValues = request.getParameterValues(paramName);
            if (paramValues == null || paramValues.length == 0) {
                continue;
            }
            StringBuilder buffer = new StringBuilder();
            for (String value : paramValues) {
                buffer.append(value);
            }
            if (buffer.toString().trim().length() == 0) {
                continue;
            }
            formChain.setRequestParameters(paramName, paramValues);
            if (Action.REQUEST_METHOD.equals(paramName)) {
                act.setMethod(request.getParameter(paramName));
            }
        }
    }
}
